using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
using Krist_em_up.Characters;
using Krist_em_up.Characters.Enemies;
using Krist_em_up.Music;
using Krist_em_up.Components;
using Krist_em_up.Plateforms;
using Krist_em_up.Level;
using Krist_em_up.Interface;
using Krist_em_up.Item;
using Krist_em_up.Interface.Gui;
using Krist_em_up.i18n;

namespace Krist_em_up
{
    public class Kristemup : GameScreen
    {
        public GraphicsDeviceManager graphics;
        protected SpriteBatch spriteBatch;
        public Kris[] tabKris;
        public Kris kris;
        public Background sol, paysage;
        protected LinkedList<Enemy> enemies;
        public int level;

        public LinkedList<Enemy> Enemies
        {
            get { return enemies; }
            set { enemies = value; }
        }
        protected List<Bonus> bonus;
        public List<Projectile> bullets;
        Enemy victim;
        bSpeed bspeed;
        bPow bpow;
        private Souris mouse;
        public Map map;
        public GameStateManager game;
        public ContentManager Content;
        public List<GameComponent> Components;
        public Vector2 origin;
        public int score;
        public bool stop;
        Texture2D backScore, separation;
        public TimeSpan time;

        protected Song backgroundSong;
        public Viewport defaultViewPort, gameViewport;

        protected GUI gui;

        protected ControlsConfig PlayerOneControls;

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="game"></param>
        public Kristemup(GameStateManager game, int level,int score) : base(game)
        {
            Content = game.Content;
            this.game = game;
            Enemies = new LinkedList<Enemy>();
            bullets = new List<Projectile>();
            bonus = new List<Bonus>();
            Components = new List<GameComponent>();
            this.level = level;
            this.score = score;
        }


        /// <summary>
        /// Initialize the components
        /// </summary>
        public override void Initialize()
        {
            origin = new Vector2(0, 0);
            time = TimeSpan.Zero;
            mouse = new Souris(game);
            Components.Add(mouse);

            sol = new Background(this, "sol", new Vector2(0, 9 * Plateform.Height));
            paysage = new Background(this, "Paysage", new Vector2(0, 0));
            tabKris = new Kris[1];
            switch (level)
            {
                case 1:
                    map = Map.LoadFromFile("1.map", game.GraphicsDevice);
                    break;
                case 2:
                    map = Map.LoadFromFile("2.map", game.GraphicsDevice);
                    break;
                default:
                    map = Map.LoadFromFile("3.map", game.GraphicsDevice);
                    break;
            }

            defaultViewPort = game.GraphicsDevice.Viewport;
            gameViewport = defaultViewPort;
            gameViewport.Height = (int)(gameViewport.Height * 4 / 5);
            //GUI.Initialize(this);

            SpawnK(map.Spawn.X, map.Spawn.Y);

            foreach (Vector2 v in map.ennemiesSpawnPositions)
            {
                SpawnE(v.X, v.Y);
            }
            stop = false;

            gui = new GUI(this);
        }
        /// <summary>
        /// Init song at the beginning of the game
        /// </summary>
        public void Launch()
        {
            try
            {
                backgroundSong = game.Content.Load<Song>("Song/RequiemForADream");
                MediaPlayer.Play(backgroundSong);
                MediaPlayer.IsRepeating = true;
            }
            catch { }

        }
        /// <summary>
        /// Load necessery content
        /// </summary>
        public override void LoadContent()
        {
            spriteBatch = new SpriteBatch(game.GraphicsDevice);
            kris.LoadContent();
            foreach (Enemy mob in Enemies)
            {
                mob.LoadContent();
            }

            //sontest = Content.Load<SoundEffect>("sound/Laser_Shoot"); // Pour le jouer c'est  : sontest.Play();
            //p.LoadContent();
            paysage.LoadContent();
            sol.LoadContent();
            //player.LoadContent();
            backScore = Content.Load<Texture2D>("pixel");
            separation = Content.Load<Texture2D>("separation");
        }

        public override void UnloadContent()
        {

        }
        /// <summary>
        /// Update the game
        /// </summary>
        /// <param name="gameTime"></param>
        public override void Update(GameTime gameTime)
        {
            time += gameTime.ElapsedGameTime;
            //Clamp origin between level limits                        
            int decal = 400;
            if (tabKris.GetLength(0) == 2)
                decal = 200;
            origin.X = kris.getPosition().X - decal;
            origin.X = MathHelper.Clamp(origin.X, 0, map.Plateforms.GetLength(0) * Plateform.Width - 800);

            //Update the caracters
            foreach (Kris joueur in tabKris)
            {
                joueur.Update(gameTime, true, Enemies);
            }

            //Update NPC
            foreach (Enemy mob in Enemies)
            {
                mob.Update(gameTime);
            }

            //Update bullets
            Projectile[] temp = new Projectile[bullets.Count];
            bullets.CopyTo(temp);

            foreach (Projectile pipiw in temp)
            {
                pipiw.Update(gameTime);
                //if (pipiw.duree(gameTime.TotalGameTime) || pipiw.touche(Enemies))
                //{
                //    bullets.Remove(pipiw);
                //}

            }

            //Update bonuses
            Bonus[] tempb = new Bonus[bonus.Count];
            bonus.CopyTo(tempb);
            foreach (Bonus boost in tempb)
            {
                if (boost.GetRec().Intersects(kris.GetRec()))
                {
                    kris.bonus(boost, gameTime);
                    bonus.Remove(boost);
                }
            }
            if (Keyboard.GetState().IsKeyDown(Keys.P))
            {
                game.PauseGame();
            }
        }

        /// <summary>
        /// Draw the game on the screen
        /// </summary>
        /// <param name="gameTime"></param>
        public override void Draw(GameTime gameTime)
        {
            game.GraphicsDevice.Viewport = gameViewport;

            paysage.Drawsol(spriteBatch, origin);

            foreach (Enemy mob in Enemies)
            {
                if (mob.IsOnScreenE(origin))
                    mob.Draw(gameTime, spriteBatch, origin, stop);
            }

            foreach (Projectile pipiw in bullets)
            {
                pipiw.Draw(gameTime, origin);
            }

            SpriteFont font = Content.Load<SpriteFont>("Fonts/Gamefont");
            spriteBatch.Begin();

            if (kris.reachEnd == true)
                spriteBatch.DrawString(font, "YOU FUCKING WON", new Vector2(game.graphics.PreferredBackBufferWidth / 2 - font.MeasureString("YOU FUCKING WON").X / 2,
                    game.graphics.PreferredBackBufferHeight / 2), Color.Red);

            //Loop over 2 dimensions of the map's plateforms
            for (int x = 0; x < map.Plateforms.GetLength(0); x++)
            {
                for (int y = 0; y < map.Plateforms.GetLength(1); y++)
                {
                    Texture2D texture = map.Plateform;
                    if (map.Plateforms[x, y].Collision == TileCollision.Impassable)
                    {
                        // Draw it in screen space.
                        Vector2 position = new Vector2(x, y) * Plateform.Size;
                        spriteBatch.Draw(texture,
                            new Rectangle((int)(position - origin).X, (int)(position - origin).Y, Plateform.Width, Plateform.Height),
                            null, Color.White);
                    }
                }
            }
            spriteBatch.End();

            foreach (Kris joueur in tabKris)
            {
                joueur.Draw(gameTime, spriteBatch, origin);
            }
            foreach (Bonus boost in bonus)
            {
                boost.DrawB(spriteBatch, origin);
            }

            game.GraphicsDevice.Viewport = defaultViewPort;

            spriteBatch.Begin();
            Color c = new Color(Color.Black, 127);
            spriteBatch.DrawString(font, Strings.temps, new Vector2(game.graphics.PreferredBackBufferWidth / 2 - font.MeasureString(Strings.temps).X / 2, 0)
                , Color.White);
            string timeString = time.Seconds.ToString();

            // Ajoute le 0 pour s < 10 (05, 01, etc)
            if (time.Seconds < 10)
                timeString = '0' + timeString;

            timeString = time.Minutes.ToString() + ":" + timeString;
            spriteBatch.DrawString(font, timeString, new Vector2(game.graphics.PreferredBackBufferWidth / 2 - font.MeasureString(timeString).X / 2,
                font.MeasureString("T").Y), Color.Black);

            string str = "Score : " + score.ToString();
            spriteBatch.Draw(backScore, new Rectangle(game.graphics.PreferredBackBufferWidth
                - (int)font.MeasureString(str).X, (int)font.MeasureString(str).Y,
                    game.graphics.PreferredBackBufferWidth, (int)font.MeasureString(str).Y), c);

            spriteBatch.DrawString(font, str, new Vector2(game.graphics.PreferredBackBufferWidth
                - font.MeasureString(str).X, font.MeasureString(str).Y), Color.Red);
            spriteBatch.Draw(separation, new Vector2(gameViewport.Width, 0), Color.White);

            if (tabKris.All<Kris>((k) => k.Lives == 0))
            {
                SpriteFont gameOver = Content.Load<SpriteFont>("Fonts/GameOver");
                spriteBatch.DrawString(gameOver, "GAME", new Vector2(defaultViewPort.Width / 2 - gameOver.MeasureString("GAME").X / 2
                    , defaultViewPort.Height / 2 - gameOver.MeasureString("GAME").Y), Color.White);
                spriteBatch.DrawString(gameOver, "OVER", new Vector2(defaultViewPort.Width / 2 - gameOver.MeasureString("OVER").X / 2
                    , defaultViewPort.Height / 2), Color.White);
            }
            spriteBatch.End();

            //GUI
            Effect e = Content.Load<Effect>("Blur");
            spriteBatch.Begin();

            e.Begin();
            foreach (EffectPass pass in e.CurrentTechnique.Passes)
            {
                pass.Begin();
            }
            spriteBatch.End();
            //GUI.drawGUI(spriteBatch, this);

            gui.Draw();

            foreach (EffectPass pass in e.CurrentTechnique.Passes)
            {
                pass.End();
            }
            e.End();

            game.GraphicsDevice.Viewport = defaultViewPort;
        }

        public override void Reset()
        {

        }

        /// <summary>
        /// Assign the given controls to player one
        /// </summary>
        /// <param name="ctrls">Controls to assign</param>
        public void SetPlayerControls(ControlsConfig ctrls)
        {
            PlayerOneControls = ctrls;
            kris.ctrls = PlayerOneControls;
        }

        public Clavier getClavier()
        {
            return game.getClavier();
        }

        /// <summary>
        /// Spawn Kris at the selected location
        /// </summary>
        /// <param name="x">Coordinate on X</param>
        /// <param name="y">Coordinate on Y</param>
        public void SpawnK(float x, float y)
        {
            kris = new Kris(this, new Vector2(x * Plateform.Width, y * Plateform.Height),
                game.settings.PlayerOne, 0);
            tabKris[0] = kris;
        }

        /// <summary>
        /// Spawn an ennemy at the selected location
        /// </summary>
        /// <param name="x">Coordinate on X</param>
        /// <param name="y">Coordinate on Y</param>
        public void SpawnE(float x, float y)
        {
            victim = new Enemy(this, new Vector2(x * Plateform.Width, y * Plateform.Height), 500);
            Enemies.AddLast(victim);
        }
        /// <summary>
        /// Spawn a speed bonus at the selected location
        /// </summary>
        /// <param name="x">Coordinate on X</param>
        /// <param name="y">Coordinate on Y</param>
        public void SpawnS(float x, float y)
        {
            bspeed = new bSpeed(this, new Vector2(x * Plateform.Width, y * Plateform.Height));
            bonus.Add(bspeed);
        }
        /// <summary>
        /// Spawn a power bonus at the selected location
        /// </summary>
        /// <param name="x">Coordinate on X</param>
        /// <param name="y">Coordinate on Y</param>
        public void SpawnP(float x, float y)
        {
            bpow = new bPow(this, new Vector2(x * Plateform.Width, y * Plateform.Height));
            bonus.Add(bpow);
        }
    }
}